/*
 * @Filename: SJA_WR.v, SJA1000 control
 * @Author: ws
 * @Description: execute the write and read operation to SJA1000
 * @Date: 2022-07-17 20:43:25
 * @LastEditTime: 2023-03-20 14:41:13
 * @Company: 662
 */

module SJA_WR(

//=========================== clk & rst ===========================//
input   wire            i_can_clk,                      //CAN_TOP clock, 125M
input   wire            i_can_rst_n,                    //i_can_clk, active low reset

//============================ SJA_WR =============================//
input	wire	[7:0]	can_ad_i,			            //input address/data from SJA_1000
output	reg	    [7:0]	can_ad_o,			            //output address/data to SJA_1000
output	reg		        can_ad_sel,			            //control can_ad signal direction
output  reg             can_cs_n,                       //SJA_1000 chip select input, low enable
output  reg             can_ale_as,                     //SJA_1000 address lock enable
output  reg             can_wr_n,                       //SJA_1000 write signal
output  reg             can_rd_n,                       //SJA_1000 read signal
output  wire            can_mode,                       //SJA_1000 mode select, 1->Intel mode is used
//input   wire            can_int_n,                      //SJA_1000 interrupt
//output  reg             can_rst_n,                      //SJA_1000 reset signal

//============================== SOI ==============================//
input   wire    [7:0]   i_soi_addr,                     //SJA_1000 address
input   wire            i_soi_wren,                     //SJA_1000 write enable
input   wire            i_soi_rden,                     //SJA_1000 read enable
input   wire    [7:0]   i_soi_din,                      //write data to SJA_1000
output  reg     [7:0]   o_soi_dout,                     //read data from SJA_1000
output  reg             o_soi_dout_valid,               //read data from SJA_1000 enable
output  reg             o_soi_opr_end_flag              //flag of read or write operation is end 

);

//================ internal reg&wire declarations =================//
reg             [7:0]   temp_addr;                      //temporarily store used address
reg             [7:0]   temp_din;                       //temporarily store writed data
reg                     temp_rd_en;

reg             [3:0]   wait_clk_cnt;                   //the counter of needed wait clock   

//FSM
reg             [3:0]   cur_sja_ctrl_s;
parameter               IDLE_S = 4'd0,
                        CLK_1_S = 4'd1,
                        CLK_2_S = 4'd2,
                        CLK_3_S = 4'd3,
                        CLK_4_S = 4'd4,
                        CLK_5_S = 4'd5,
                        CLK_9_RD_S = 4'd6,
                        CLK_9_WR_S = 4'd7,
                        CLK_10_S = 4'd8,
                        CLK_11_S = 4'd9,
                        CLK_13_S = 4'd10,
                        CLK_14_S = 4'd11;


//====================== assign wire control ======================//
assign  can_mode = 1'b1;                                //1->Intel mode is used 


//=========== sja_1000 write&read function always block ===========//
always @(posedge i_can_clk or negedge i_can_rst_n)begin
    if(!i_can_rst_n)begin
        
        //output data to SJA_1000
        can_cs_n <= 1'b1;
        can_ale_as <= 1'b0;
        can_wr_n <= 1'b1;
        can_rd_n <= 1'b1;
        can_ad_o <= 8'b0;
        can_ad_sel <= 1'b0;
        
        //output data to OPR_PARSE
        o_soi_dout <= 8'b0;
        o_soi_dout_valid <= 1'b0;
        o_soi_opr_end_flag <= 1'b0;

        //other control signal
        temp_addr <= 8'b0;
        temp_din <=  8'b0;
        temp_rd_en <= 1'b0;
        wait_clk_cnt <= 4'b0;

        //FSM
        cur_sja_ctrl_s <= IDLE_S;

    end

    else begin

        o_soi_dout <= can_ad_i;

        case(cur_sja_ctrl_s)

            IDLE_S:begin
                //output data to SJA_1000
                can_cs_n <= 1'b1;
                can_wr_n <= 1'b1;
                can_rd_n <= 1'b1;
                can_ad_o <= 8'b0;
                can_ad_sel <= 1'b0;

                //output data to OPR_PARSE
                o_soi_dout_valid <= 1'b0;
                o_soi_opr_end_flag <= 1'b0;

                //other control signal
                //temp_addr <= i_soi_addr;
                wait_clk_cnt <= 4'b0;

                if(i_soi_wren || i_soi_rden)begin       //already start write or read data, set can_ale_as signal high at start of the 1st clock 
                    can_ale_as <= 1'b1;

                    temp_addr <= i_soi_addr;
                    temp_din <= i_soi_din;
                    temp_rd_en <= i_soi_rden;

                    cur_sja_ctrl_s <= CLK_1_S;
                end
                else begin
                    can_ale_as <= 1'b0;

                    temp_addr <= 8'b0;
                    temp_din <=  8'b0;
                    temp_rd_en <= 1'b0;

                    cur_sja_ctrl_s <= IDLE_S;
                end
            end

            CLK_1_S:begin                               //set address at start of the 2nd clock -> 8ns
                can_ad_o <=  temp_addr;
                cur_sja_ctrl_s <= CLK_2_S;
            end

            CLK_2_S:begin
                cur_sja_ctrl_s <= CLK_3_S;              //wait
            end

            CLK_3_S:begin                               //set can_ale_as signal low, at start of the 4th clock -> 24ns
                can_ale_as <= 1'b0;
                cur_sja_ctrl_s <= CLK_4_S;
            end

            CLK_4_S:begin                               
                can_ad_o <= 8'b0;                       //release address at start of the 5th -> 32ns
                can_cs_n <= 1'b0;                       //set can_cs_n signal low, low is valid
                cur_sja_ctrl_s <= CLK_5_S; 
            end

            CLK_5_S:begin
                wait_clk_cnt <= 4'b0;
                if(temp_rd_en)begin                     //command: read data from SJA_1000
                    can_rd_n <= 1'b0;
                    can_ad_sel <= 1'b1;
                    cur_sja_ctrl_s <= CLK_9_RD_S;
                end
                else begin                              //command: write data to SJA_1000
                    can_wr_n <= 1'b0;
                    can_ad_o <= temp_din;
                    cur_sja_ctrl_s <= CLK_9_WR_S;
                end
            end

            CLK_9_RD_S:begin
                temp_rd_en <= 1'b0;
                wait_clk_cnt <= wait_clk_cnt + 1'b1;
                if(4'd8 == wait_clk_cnt)begin
                    o_soi_dout_valid <= 1'b1;
                    cur_sja_ctrl_s <= CLK_13_S;
                end
            end

            CLK_9_WR_S:begin                            //release write operation at start of the 10th clock -> 72ns
                wait_clk_cnt <= wait_clk_cnt + 1'b1;
                if(4'd3 == wait_clk_cnt)begin
                    can_wr_n <= 1'b1;
                    cur_sja_ctrl_s <= CLK_10_S;
                end
            end

            CLK_10_S:begin                              //release can_cs_n signal at start of the 11th clock -> 80ns
                can_cs_n <= 1'b1;
                cur_sja_ctrl_s <= CLK_11_S;
            end

            CLK_11_S:begin
                o_soi_opr_end_flag <= 1'b1;
                cur_sja_ctrl_s <= IDLE_S;
            end

            CLK_13_S:begin                              //release read operation at start of the 14th clock -> 104ns
                o_soi_dout_valid <= 1'b0;
                wait_clk_cnt <= wait_clk_cnt + 1'b1;
                if(4'd10 == wait_clk_cnt)begin
                    can_rd_n <= 1'b1;
                    cur_sja_ctrl_s <= CLK_14_S;
                end
            end

            CLK_14_S:begin                              //release can_cs_n signal at start of the 15th clock -> 112ns
                wait_clk_cnt <= wait_clk_cnt + 1'b1;
                can_cs_n <= 1'b1;
                if(4'd14 == wait_clk_cnt)begin
                    o_soi_opr_end_flag <= 1'b1;
                    can_ad_sel <= 1'b0;
                    cur_sja_ctrl_s <= IDLE_S;
                end
            end

            default:begin
                cur_sja_ctrl_s <= IDLE_S;
            end

        endcase

    end
end


endmodule
